#import "BWInspector.h"
#import "BWInspectorPane.h"
#import "BWBorkStitchDocument.h"


@interface BWInspector (ForwardReferences)

- (void) moveToPane: (BWInspectorPane *) pane;

@end // ForwardReferences


@implementation BWInspector

+ (BWInspector *) sharedInspector
{
    static BWInspector *s_inspector;

    if (s_inspector == nil) {
        s_inspector = [[BWInspector alloc] 
                          initWithWindowNibName: @"BWInspector"];
        assert (s_inspector != nil);

        // force loading of nib
        (void) [s_inspector window];
    }

    return (s_inspector);

} // sharedInspector


- (float) titleBarHeight
{
    NSRect frame = NSMakeRect (0, 0, 100, 100);

    NSRect contentRect;
    contentRect = [NSWindow contentRectForFrameRect: frame
                            styleMask: NSTitledWindowMask];

    return (frame.size.height - contentRect.size.height);

} // titleBarHeight


- (BWInspectorPane *) paneWithName: (NSString *) name
{
    if (name == nil) {
        return (nil);
    }

    BWInspectorPane *foundPane = nil;
    int i;
    for (i = 0; i < [panes count]; i++) {
        BWInspectorPane *pane;
        pane = [panes objectAtIndex: i];
        
        if ([[pane paneName] isEqualToString: name]) {
            foundPane = pane;
            break;
        }
    }

    return (foundPane);

} // paneWithName


- (void) show
{
    if (currentPane == nil) {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        
        NSString *name = [defaults objectForKey: @"BWInspectorLastSelectedPane"];

        BWInspectorPane *pane = [self paneWithName: name];

        if (pane == nil) {
            pane = [panes objectAtIndex: 0];
        }

        [self moveToPane: pane];
        
        // the height of everything we have
        NSRect paneFrame = [[currentPane paneView] frame];
        NSRect matrixFrame = [buttonMatrix frame];

        float height;
        height = paneFrame.size.height + matrixFrame.size.height 
            + [self titleBarHeight];

        // now fix up the window size
        NSRect windowFrame = [[self window] frame];

        // the bottom-left origin is a real PITA when dealing with
        // window coordinates.  With a top-left origin, we can just set
        // the height of the window to what we want.  But we have to
        // move the origin so that it stays in the same place
        float delta = height - windowFrame.size.height;

        windowFrame.origin.y -= delta;
        windowFrame.size.height += delta;

        [[self window] setFrame: windowFrame
                       display: YES];
    }

    [self showWindow: self];

} // show


- (id) initWithWindow: (NSWindow *) window
{
    if (self = [super initWithWindow: window]) {
        panes = [[NSMutableArray alloc] init];
        
        NSNotificationCenter *center;
        center = [NSNotificationCenter defaultCenter];
        
        [center addObserver: self
                selector: @selector(documentActivateNotification:)
                name: BWBorkStitchDocument_DocumentActivateNotification
                object: nil];
        
        [center addObserver: self
                selector: @selector(documentDeactivateNotification:)
                name: BWBorkStitchDocument_DocumentDeactivateNotification
                object: nil];

        [self setWindowFrameAutosaveName: @"BWInspectorWindow"];
    }
    
    return (self);

} // initWithWindow


- (void) dealloc
{
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    [center removeObserver: self
            name: nil
            object: nil];

    [panes release];

    [super dealloc];

} // dealloc


- (void) moveToPane: (BWInspectorPane *) pane
{
    if (pane == currentPane) {
        return;
    }

    NSView *oldView, *newView;

    oldView = [currentPane paneView];
    newView = [pane paneView];

    [contentBox addSubview: newView];

    [oldView setHidden: YES];
    [newView setHidden: YES];

    // bail out if there is no current pane, so this will be the
    // first time through
    if (currentPane == nil) {
        // this is before the window is shown, so don't worry about
        // window resizage
        goto done;
    }

    // figure out new window frame size
    NSRect paneFrame = [[pane paneView] frame];
    NSRect currentPaneFrame = [[currentPane paneView] frame];

    NSRect windowFrame = [[self window] frame];
    float delta = currentPaneFrame.size.height - paneFrame.size.height;
    
    NSRect newWindowFrame = windowFrame;
    newWindowFrame.origin.y += delta;
    newWindowFrame.size.height -= delta;

    // see block at end with view animation code, if it gets fixed

    [[self window] setFrame: newWindowFrame
                   display: YES
                   animate: YES];

    // save the current pane to the prefs
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject: [pane paneName]
              forKey: @"BWInspectorLastSelectedPane"];

done:
    currentPane = pane;
    [newView setHidden: NO];

    // out with the old pane
    [oldView removeFromSuperview];

} // moveToPane


- (IBAction) matrixSelectionChange: (id) sender
{
    int index = [sender selectedColumn];

    if (index >= [panes count]) {
        return;
    }

    // and in with the new
    BWInspectorPane *pane;
    pane = [panes objectAtIndex: index];

    [self moveToPane: pane];

} // matrixSelectionChange


- (void) addPane: (BWInspectorPane *) pane
{
    // don't add if already there
    if ([panes containsObject: pane]) {
        return;
    }

    int index = [panes count];

    [panes addObject: pane];

    NSImage *icon = [pane toolbarIcon];
    
    // put in matrix for next index
    id cell = [[buttonMatrix cells] objectAtIndex: index];
    [cell setImage: icon];

} // addPane


- (void) setDocument: (NSDocument *) document
{
    [super setDocument: document];

    int i;
    for (i = 0; i < [panes count]; i++) {
        BWInspectorPane *pane = [panes objectAtIndex: i];
        [pane setDocument: (BWBorkStitchDocument *)document];
    }

} // setDocument


- (void) documentActivateNotification: (NSNotification *) notification
{
    NSDocument *document = [notification object];
    [self setDocument: document];

} // documentActivateNotification


- (void) documentDeactivateNotification: (NSNotification *) notification
{
    [self setDocument: nil];

} // documentDeactivateNotification


- (void) showWindow: (id) sender
{
    [self setDocument: [[NSDocumentController sharedDocumentController]
                           currentDocument]];

    [super showWindow: self];

} // show


- (NSString *) windowTitleForDocumentDisplayName: (NSString *) displayName
{
    NSString *string;

    string = [NSString stringWithFormat: @"Inspector for %@", displayName];
    return (string);

} // windowTitleForDocumentDisplayName


- (void) updatePaneUI
{
    int i;
    for (i = 0; i < [panes count]; i++) {
        BWInspectorPane *pane = [panes objectAtIndex: i];
        [pane updateUI];
    }

} // updatePaneUI


- (NSString *) autosaveName
{
    return (@"BWInspector");
} // autosaveName

@end // BWInspector


#if NS_VIEW_ANIMATION_BROKEN
    // bug # 4244279.  window resizing ends up being a couple of
    // pixels off.  If/when that is fixed, use this.  It's cooler.

    NSDictionary *windowResize;
    windowResize = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [self window], NSViewAnimationTargetKey, 
                                 [NSValue valueWithRect: newWindowFrame],
                                 NSViewAnimationEndFrameKey,
                                 nil];

    NSDictionary *oldFadeOut = nil;
    if (oldView != nil) {
        oldFadeOut = [NSDictionary dictionaryWithObjectsAndKeys:
                                       oldView, NSViewAnimationTargetKey, 
                                   NSViewAnimationFadeOutEffect,
                                   NSViewAnimationEffectKey, nil];
    }

    NSDictionary *newFadeIn = nil;
    newFadeIn = [NSDictionary dictionaryWithObjectsAndKeys:
                                  newView, NSViewAnimationTargetKey, 
                              NSViewAnimationFadeInEffect,
                              NSViewAnimationEffectKey, nil];
    newFadeIn = nil;

    NSArray *animations;
    animations = [NSArray arrayWithObjects:
                              windowResize, newFadeIn, oldFadeOut, nil];

    NSViewAnimation *animation;
    animation = [[NSViewAnimation alloc]
                    initWithViewAnimations: animations];
    [animation setAnimationBlockingMode: NSAnimationBlocking];
    [animation setDuration: 0.5];
    [animation startAnimation];
    [animation release];
#endif
